﻿using System.Data;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.WebPages;
using Autofac;
using Autofac.Integration.Mvc;
using SlamCms.Caching;
using SlamCms.Common;
using SlamCms.Data;
using SlamCms.Data.Repositories;
using SlamCms.DomainEvents;
using SlamCms.Logging;
using SlamCms.Profiling;
using SlamCms.SharePointServices;
using SlamCms.Tracking;
using SlamCms.Web;
using SlamCms.Web.Mvc;
using AuthenticationService = SlamCms.Common.Security.AuthenticationService;

namespace SlamCms.Bootstrappers
{
	public class SlamCmsBootstrapper : Bootstrapper
	{
		public SlamCmsBootstrapper() : base(BootstrapperPriority.High)
		{
		}

		public override void PreApplicationStart(PreApplicationStartContext context)
		{
			InitializeMvc();

			RegisterDependecies(context);
		}

		public override void PostApplicationStart(PostApplicationStartContext context)
		{
			RegisterRoutes(context);
		}

		protected void InitializeMvc()
		{
			MvcHandler.DisableMvcResponseHeader = true;

			AreaRegistration.RegisterAllAreas();

			ValueProviderFactories.Factories.Add(new CookieValueProviderFactory());

			GlobalFilters.Filters.Add(new TrackingAttribute());

			var precompiledViewEngine = new SlamCmsPrecompiledViewEngine(Assembly.GetExecutingAssembly());

			// StartPage lookups are done by WebPages. 
			VirtualPathFactoryManager.RegisterVirtualPathFactory(precompiledViewEngine);

			ViewEngines.Engines.Clear();
			ViewEngines.Engines.Add(new SlamCmsViewEngine());
			ViewEngines.Engines.Add(precompiledViewEngine);
		}

		protected void RegisterDependecies(PreApplicationStartContext context)
		{
			var builder = context.ContainerBuilder;

			// MVC
			builder.RegisterModelBinders(typeof(SlamCmsContext).Assembly);
			builder.RegisterModelBinderProvider();
			builder.RegisterType<SlamModelBinderProvider>().As<IModelBinderProvider>();
			builder.RegisterFilterProvider();

			// register controllers
			foreach (var assembly in TypeHelpers.GetAssemblies())
			{
				builder.RegisterControllers(assembly)
					   .PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies);

				builder.RegisterAssemblyTypes(assembly)
					   .AsClosedTypesOf(typeof(IDomainEventHandler<>));
			}

			builder.RegisterModule<AutofacWebTypesModule>();
			builder.RegisterType<DefaultBaseUriResolver>().As<IBaseUriResolver>();
			builder.RegisterType<CookieManager>().As<ICookieManager>();
			builder.RegisterType<FormsAuthenticationWrapper>().As<IFormsAuthentication>();
			builder.Register(c => new UrlHelper(c.Resolve<HttpContextBase>().Request.RequestContext)).InstancePerHttpRequest();
			
			// default registrations
			builder.RegisterType<HttpRuntimeCacheManager>().AsSelf().As<ICacheManager>();
			builder.RegisterType<DefaultLogManager>().AsSelf().As<ILogManager>();
			builder.RegisterType<MiniProfilerWrapper>().As<IProfiler>();

			builder.RegisterType<AuthenticationService>();
			builder.RegisterType<TrackingService>().As<ITrackingService>();
			builder.RegisterType<UrlHandlerRouterRegistrar>();

			builder.RegisterType<UrlHandlerRepository>().As<IUrlHandlerRepository>();
			builder.RegisterType<TrackingRepository>().As<ITrackingRepository>().InstancePerHttpRequest();
			builder.RegisterType<ContentItemRepository>().As<IContentItemRepository>();

			// current user resolver
			builder.RegisterType<DefaultSlamCmsUserResolver>().As<ISlamCmsUserResolver>();

			// sharepoint services
			builder.RegisterType<SharePointImageService>();
			builder.RegisterType<SharePointDocumentService>();

			// database connection resolver
			builder.RegisterType<MiniProfilerDbConnectionResolver>().As<IDbConnectionResolver>();
			builder.Register(c =>
			{
				var profiler = c.Resolve<IProfiler>();
				using (profiler.Step("[SlamCMS] Open DB connection"))
					return c.Resolve<IDbConnectionResolver>().GetConnection();
			}).As<IDbConnection>().InstancePerHttpRequest();

			// register configuration
			builder.Register(c => SlamCmsConfiguration.Instance).SingleInstance();

			// data context
			builder.RegisterType<DataContext>().InstancePerHttpRequest();

			// settings and slamcontext
			builder.RegisterType<SlamCmsContext>().InstancePerHttpRequest();

			// domain events
			DomainEventsManager.Dispatcher = new DependencyResolverEventDispatcher();				
		}

		protected void RegisterRoutes(PostApplicationStartContext context)
		{
			var routes = RouteTable.Routes;
			RegisterUrlHandlers(context, routes);
		}

		protected void RegisterUrlHandlers(PostApplicationStartContext context, RouteCollection routes)
		{
			var urlHandlerRouteRegistrar = context.BootstrapperLifetimeScope.Resolve<UrlHandlerRouterRegistrar>();
			urlHandlerRouteRegistrar.RegisterRoutes(routes);
		}
	}
}